/**
 * Copyright (C) 2009 All Rights Reserved
 * @author sebastian chang
 * @brief practice
 */

#ifndef _THREAD_QUEUE_H_
#define _THREAD_QUEUE_H_

#include <list>
#include <iostream>
#include <algorithm>

#include "auto_lock.h"
#include "mutex_lock.h"
#include "thread_event.h"

namespace trident {

template<typename type_t>
class thread_queue_t
{
public:
    /**
     * @brief constructor
     */
    thread_queue_t();

    /**
     * @brief destructor
     */
    ~thread_queue_t();

    /**
     * @brief initializes the thread queue
     * @return int
     */
    int init();

    /**
     * @brief pop up content
     * @param type_t& data_
     * @param unsigned long timeout_ 0xFFFFFFFF is infinity, which is millisecond
     * @return int
     */
     int pop(type_t& data_, unsigned long time_out_ = 0xFFFFFFFF);

    /**
     * @brief get list container size
     * @return int
     */
    int push(type_t& data_, bool push_back_ = true);

    /**
     * @brief get list container size
     * @return size_t the size of list
     */
    void clear();

    /**
     * @brief get list container size
     * @return size_t the size of list
     */
    size_t size();

private:

    std::list<type_t>           _container;     ///> the list container
    thread_event_t              _event;         ///> the thread event
    mutex_lock_t                _lock;          ///> pthread mutex lock
};

template<typename type_t>
thread_queue_t<type_t>::thread_queue_t()
{
    // Empty
}

template<typename type_t>
thread_queue_t<type_t>::~thread_queue_t()
{
    clear();
}

template<typename type_t>
int thread_queue_t<type_t>::init()
{
    int ret = -1;

    if (0 == _lock.init())
    {
        ret = _event.init();
    }

    return ret;
}

template<typename type_t>
int thread_queue_t<type_t>::pop(type_t& data_, unsigned long time_out_)
{
    int ret = -1;

    if (0 == (ret = _event.waitEvent(time_out_)))
    {
        auto_lock_t auto_lock(&_lock);

        if (_container.empty())
        {
            // TODO bug, it should not empty
            return ETIMEDOUT;
        }

        data_ = _container.front();
        _container.pop_front();
    }

    return ret;
}

template<typename type_t>
int thread_queue_t<type_t>::push(type_t& data_, bool push_back_)
{
    int ret = -1;

    auto_lock_t auto_lock(&_lock);

    if (0 == (ret = _event.setEvent()))
    {
        if (push_back_)
        {
            _container.push_back(data_);
        }
        else
        {
            _container.push_front(data_);
        }
    }

    return ret;
}

template<typename type_t>
void thread_queue_t<type_t>::clear()
{
    auto_lock_t auto_lock(&_lock);

    _container.clear();
}

template<typename type_t>
size_t thread_queue_t<type_t>::size()
{
    auto_lock_t auto_lock(&_lock);

    return _container.size();
}

} // namespace trident

#endif // _THREAD_QUEUE_H_

